package com.real.fact.web.sale.domain;

import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Property;
import org.hibernate.criterion.Restrictions;
import org.hibernate.criterion.Subqueries;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.real.fact.web.application.RealPaging;
import com.real.fact.web.customer.domain.Customer;

/**
 *
 * @since Jul 3, 2011
 */
public class SaleRepository extends HibernateDaoSupport {
  
  public void save(final Sale sale) {
    getSession().save(sale);
  }
  
  public void save(final SalePayment salePayment) {
    getSession().save(salePayment);
  }

  @SuppressWarnings("unchecked")
  public List<Sale> findAll(final RealPaging paging) {
    Criteria criteria = getSession().createCriteria(Sale.class);
    paging.setRealTotalPageNumber(criteria.list().size());
    criteria.setFirstResult(paging.getPageNumber() * paging.getPageSize());
    criteria.setMaxResults(paging.getPageSize());
    criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
    return criteria.list();
  }
  
  @SuppressWarnings("unchecked")
  public List<Sale> findAll() {
    Criteria criteria = getSession().createCriteria(Sale.class);
    criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
    return criteria.list();
  }

  @SuppressWarnings("unchecked")
  public Sale findById(long saleId) {
    Criteria criteria = getSession().createCriteria(Sale.class);
    criteria.add(Restrictions.eq("id", saleId));
    List<Sale> results= criteria.list();
    if (results.size() > 0) {
      return results.iterator().next();
    }
    return null;
  }

  @SuppressWarnings("unchecked")
  public List<Sale> filter(RealPaging paging, SaleFilter filter) {
    Criteria criteria = getSession().createCriteria(Sale.class, "sale");
    //filter dates
    if (filter.getDateFrom() != null) {
      criteria.add(Restrictions.ge("date", filter.getDateFrom()));
    }
    if (filter.getDateEnd() != null) {
      criteria.add(Restrictions.le("date", filter.getDateEnd()));
    }
    //filter tickets
    if (filter.getTicketTypes().size() > 0) {
      DetachedCriteria dc = DetachedCriteria.forClass(SalePayment.class);
      dc.createAlias("payment", "p");
      dc.createAlias("sale", "s");
      dc.setProjection(Projections.property("id"));
      dc.add(Property.forName("s.id").eqProperty("sale.id"));
      dc.add(Restrictions.in("p.ticket", filter.getTicketTypes()));
      criteria.add(Subqueries.exists(dc));
          
    }    
    
    if (filter.getPayedOption() == SaleFilter.PayedFilter.ONLY_UNPAYED) {
      DetachedCriteria dc = DetachedCriteria.forClass(SalePayment.class);
      dc.createAlias("sale", "s");
      dc.setProjection(Projections.sum("amount"));
      dc.add(Property.forName("s.id").eqProperty("sale.id"));

      //if sale.total > what customer payed ==> not totally payed
      criteria.add(Subqueries.propertyGt("total", dc)); 
    }
    
    if (filter.getPayedOption() == SaleFilter.PayedFilter.ONLY_PAYED) {
      DetachedCriteria dc = DetachedCriteria.forClass(SalePayment.class);
      dc.createAlias("sale", "s");
      dc.setProjection(Projections.sum("amount"));
      dc.add(Property.forName("s.id").eqProperty("sale.id"));
      criteria.add(Subqueries.propertyLe("total", dc)); //should be just eq(), but just in case...
    }
    
    if (paging != null) {
      paging.setRealTotalPageNumber(criteria.list().size());
      criteria.setFirstResult(paging.getPageNumber() * paging.getPageSize());
      criteria.setMaxResults(paging.getPageSize());
    }
    return criteria.list();
  }

  @SuppressWarnings("unchecked")
  public List<Seller> findSellers(RealPaging paging) {
    Criteria criteria = getSession().createCriteria(Seller.class);
    criteria.setFirstResult(paging.getPageNumber() * paging.getPageSize());
    criteria.setMaxResults(paging.getPageSize());
    return criteria.list();
  }

  @SuppressWarnings("unchecked")
  public Seller findSellerById(long sellerId) {
    Criteria criteria = getSession().createCriteria(Seller.class);
    criteria.add(Restrictions.eq("id", sellerId));    
    List<Seller> results= criteria.list();
    if (results.size() > 0) {
      return results.iterator().next();
    }
    return null;    
  }

  public void save(final Seller seller) {
    getSession().save(seller);    
  }

  @SuppressWarnings("unchecked")
  public List<Sale> getSalesByCustomer(Customer customer) {
    Criteria criteria = getSession().createCriteria(Sale.class);
    criteria.add(Restrictions.eq("customer", customer));
    criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
    return criteria.list();
  }
  
}
